using System;
using UnityEngine;
using VoxelGame.World;

namespace VoxelGame.Utils
{
	public class PerformanceManager : MonoBehaviour
	{
		[Serializable]
		private struct FogDensityByFarClip
		{
			public float farClip;

			public float fogDensity;
		}

		public enum DevicePerformance
		{
			Lowest,
			Low,
			Default
		}

		[SerializeField]
		private int _targetFPS = 20;

		[SerializeField]
		private float _targetFPSIntervalThreshold = 2f;

		[SerializeField]
		private float _updateInterval = 0.1f;

		[SerializeField]
		private float _minFarClipValue = 50f;

		[SerializeField]
		private float _mediumFarClipValue = 70f;

		[SerializeField]
		private Camera _camera;

		[SerializeField]
		private ChangeCameraCulling _cameraCulling;

		[SerializeField]
		private GameObject[] _disableObjects;

		private bool _isObjectsDisabled;

		private float _accum;

		private int _frames;

		private float _timeleft;

		private float _intervalTimeLeft;

		private float _farClipPlane;

		public Color FogColor
		{
			get;
			set;
		}

		public float FarClipPlane => _farClipPlane;

		private void Awake()
		{
			DefaultFogSettings();
			switch (GetDevicePerformanceLevel())
			{
			case DevicePerformance.Lowest:
				_cameraCulling.enabled = false;
				Shader.globalMaximumLOD = 125;
				ClipFarDistance(_minFarClipValue);
				break;
			case DevicePerformance.Low:
				_cameraCulling.enabled = false;
				Shader.globalMaximumLOD = 155;
				ClipFarDistance(_mediumFarClipValue);
				break;
			case DevicePerformance.Default:
				_cameraCulling.enabled = true;
				Shader.globalMaximumLOD = 250;
				break;
			}
		}

		public static bool IsLowEndDevice()
		{
			DevicePerformance devicePerformanceLevel = GetDevicePerformanceLevel();
			return devicePerformanceLevel == DevicePerformance.Lowest || devicePerformanceLevel == DevicePerformance.Low;
		}

		public static DevicePerformance GetDevicePerformanceLevel()
		{
			if (Application.platform == RuntimePlatform.Android)
			{
				if (SystemInfo.graphicsShaderLevel <= 35 || SystemInfo.processorCount < 4 || SystemInfo.systemMemorySize <= 1024 || SystemInfo.graphicsMemorySize <= 256 || SystemInfo.processorFrequency < 1500)
				{
					return DevicePerformance.Lowest;
				}
			}
			else if (Application.platform != RuntimePlatform.IPhonePlayer)
			{
			}
			return DevicePerformance.Default;
		}

		private void ClipFarDistance(float farClipPlane = -1f)
		{
			DisableObjects();
			if (farClipPlane >= 0f)
			{
				_farClipPlane = Mathf.Max(farClipPlane);
			}
			else
			{
				_farClipPlane = Mathf.Max(_camera.farClipPlane / 2f, _minFarClipValue);
			}
			_camera.farClipPlane = _farClipPlane;
			_intervalTimeLeft = _targetFPSIntervalThreshold;
			EnableFog(_farClipPlane);
		}

		private void Start()
		{
			_timeleft = _updateInterval;
			_intervalTimeLeft = _targetFPSIntervalThreshold;
			_farClipPlane = _camera.farClipPlane;
		}

		private void OnDestroy()
		{
			DefaultFogSettings();
		}

		private void Update()
		{
			_timeleft -= Time.deltaTime;
			_accum += Time.timeScale / Time.deltaTime;
			_frames++;
			if (!(_timeleft <= 0f))
			{
				return;
			}
			float num = _accum / (float)_frames;
			if (num < (float)_targetFPS)
			{
				_intervalTimeLeft -= _updateInterval + _timeleft;
				if (_intervalTimeLeft <= 0f)
				{
					ClipFarDistance();
				}
			}
			else
			{
				_intervalTimeLeft = _targetFPSIntervalThreshold;
			}
			_timeleft = _updateInterval;
			_accum = 0f;
			_frames = 0;
		}

		private void DefaultFogSettings()
		{
			Shader.DisableKeyword("FOG_ON");
			RenderSettings.fog = false;
			RenderSettings.fogColor = FogColor;
			SetFogPlanes(_camera.farClipPlane);
		}

		private void EnableFog(float farClipPlane)
		{
			Shader.EnableKeyword("FOG_ON");
			RenderSettings.fog = true;
			SetFogPlanes(_farClipPlane);
		}

		private static void SetFogPlanes(float farPlaneClip)
		{
			float num = 7.5f;
			Shader.SetGlobalFloat("_fogNearClipPlane", farPlaneClip - num);
			Shader.SetGlobalFloat("_fogDeltaClipPlane", num);
		}

		private void DisableObjects()
		{
			if (!_isObjectsDisabled)
			{
				_isObjectsDisabled = true;
				GameObject[] disableObjects = _disableObjects;
				foreach (GameObject gameObject in disableObjects)
				{
					gameObject.gameObject.SetActive(value: false);
				}
			}
		}
	}
}
